package hopfield;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.imageio.ImageIO;

import utility.Matrix;

public class Begin {
	
	private static Matrix[] m;
	
	public static String[][] NUMS = new String[][]  {
		{"0","0000000000000000000000000000000000000000000000000001100000000000001001000000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000010000000000010010000000000000110000000000000000000000000000000000000000000"},
		{"1","0000000000000000000000000000000000000000000000000001000000000000011100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000011111000000000000000000000000000000000000000000"},
		{"2","0000000000000000000000000000000000000000000000000011110000000000010000100000000001000010000000000100001000000000000001000000000000000100000000000000100000000000000100000000000000100000000000000100001000000000011111100000000000000000000000000000000000000000"},
		{"3","0000000000000000000000000000000000000000000000000011110000000000010000100000000001000010000000000000010000000000000110000000000000000100000000000000001000000000000000100000000001000010000000000100010000000000001110000000000000000000000000000000000000000000"},
		{"4","0000000000000000000000000000000000000000000000000000010000000000000011000000000000010100000000000010010000000000001001000000000001000100000000000100010000000000011111100000000000000100000000000000010000000000000111100000000000000000000000000000000000000000"},
		{"5","0000000000000000000000000000000000000000000000000111111000000000010000000000000001000000000000000100000000000000010110000000000001100100000000000000001000000000000000100000000001000010000000000100010000000000001110000000000000000000000000000000000000000000"},
		{"5","0000000000000000000001111111100000001100000000000000100000000000000010000000000000001000000000000000111111111000000000000000110000000000000001100000000000000110000000000000001000001100000000100000010000000110000001111000110000000000111111000000000000000000"},
		{"6","0000000000000000000000000000000000000000000000000001110000000000001001000000000001000000000000000100000000000000010110000000000001100100000000000100001000000000010000100000000001000010000000000010010000000000000110000000000000000000000000000000000000000000"},
		{"7","0000000000000000000000000000000000000000000000000111111000000000010001000000000001000100000000000000100000000000000010000000000000010000000000000001000000000000000100000000000000010000000000000001000000000000000100000000000000000000000000000000000000000000"},
		{"8","0000000000000000000000000000000000000000000000000011110000000000010000100000000001000010000000000100001000000000001001000000000000011000000000000010010000000000010000100000000001000010000000000100001000000000001111000000000000000000000000000000000000000000"},
		{"9","0000000000000000000000000000000000000000000000000001100000000000001001000000000001000010000000000100001000000000010000100000000000100110000000000001101000000000000000100000000000000010000000000010010000000000001110000000000000000000000000000000000000000000"},
		{"0","0000000000000000000000000000000000000000000000000011110000000000011001000000000001000010000000000100001000000000010000100000000001000010000000000100001000000000010000100000000001000110000000000010110000000000000110000000000000000000000000000000000000000000"},
		{"1","0000000000000000000000000000000000000000000000000000100000000000000110000000000001111000000000000101100000000000000110000000000000011000000000000001100000000000000110000000000000011000000000000001100000000000000110000000000000000000000000000000000000000000"},
		{"2","0000000000000000000000000000000000000000000000000011110000000000011001100000000001000010000000000000011000000000000001000000000000001100000000000000100000000000000100000000000000100000000000000111111000000000011111100000000000000000000000000000000000000000"},
		{"3","0000000000000000000000000000000000000000000000000011110000000000011001100000000001000010000000000000011000000000000011000000000000001100000000000000011000000000000000100000000001000010000000000110110000000000000110000000000000000000000000000000000000000000"},
		{"4","0000000000000000000000000000000000000000000000000000010000000000000011000000000000011100000000000001010000000000001001000000000001100100000000000100010000000000111111110000000000000100000000000000010000000000000001000000000000000000000000000000000000000000"},
		{"5","0000000000000000000000000000000000000000000000000011111000000000011000000000000001000000000000000101000000000000011111000000000001000110000000000000001000000000000000100000000011000110000000000110110000000000001110000000000000000000000000000000000000000000"},
		{"6","0000000000000000000000000000000000000000000000000000100000000000000110000000000000010000000000000011000000000000011111000000000001100010000000000100001100000000010000110000000001000010000000000110011000000000001111000000000000000000000000000000000000000000"},
		{"7","0000000000000000000000000000000000000000000000000111111000000000000000100000000000000110000000000000010000000000000011000000000000001000000000000001100000000000000100000000000000010000000000000011000000000000001100000000000000000000000000000000000000000000"},
		{"8","0000000000000000000000000000000000000000000000000011110000000000010001100000000001000010000000000100011000000000011111000000000001111100000000000100001000000000110000100000000001000010000000000110011000000000001111000000000000000000000000000000000000000000"},
		{"9","0000000000000000000000000000000000000000000000000011110000000000010001100000000011000010000000001100001000000000110001100000000001101100000000000011110000000000000010000000000000011000000000000001000000000000001100000000000000000000000000000000000000000000"},

	};
	
	public static void main(String[] argu) {
		m = getNumberMatrix();
		Matrix w = m[0].inverse().multiply(m[0]);
		for (int i=1; i<m.length; i++) {
			Matrix t = m[i].inverse().multiply(m[i]);
			w = w.add(t);
		}

		
		System.out.println(w.getRowCount() + " " + w.getColCount());
		w = w.add(Matrix.getI(w.getRowCount()).multiply(-m.length));
		System.out.println(w);

		System.out.println(" ================ ");

		//examine(w, "images/number/1.bmp", 1);
		//examine(w, "images/number/2.bmp", 2);
		examine(w, "images/number/5.bmp", 5);
		examine(w, "images/number/6.bmp", 6);
		examine(w, "images/number/7.bmp", 7);	
	}

	private static Matrix[] getNumberMatrix() {
		Matrix[] r = new Matrix[NUMS.length];
		for (int i=0; i<NUMS.length; i++) {
			String[] n = NUMS[i];
			String f = n[1];
			String sn = n[0];
			int in = Integer.parseInt(sn);
			r[i] = getNumberMatrix(in, f);
		}
		return r;
	}

	private static Matrix getNumberMatrix(int n, String f) {
		int t[] = new int[f.length()];

		for (int i=0; i<f.length(); i++) {
			char c = f.charAt(i);
			t[i] = (c == '0' ? -1: 1);
		}
		return new Matrix(t);
	}

	private static void examine(Matrix w, String file, int exp) {
		try {
			int[] t = test(w, file);
			List<RegResult> list = new ArrayList<RegResult>();
			for (int i=0; i<NUMS.length; i++) {
				String n = NUMS[i][0];
				int d = diff(t, m[i]);
				RegResult r = new RegResult(Integer.valueOf(n), d);
				list.add(r);
			}
			Collections.sort(list);
			System.out.println(" exp = " + exp);
			for (int i=0; i<NUMS.length; i++) {
				System.out.println(list.get(i));
			}
		} catch (IOException e) {
			System.out.println("IOException: " + e.getMessage());
		}

	}

	private static int diff(int[] t, Matrix matrix) {
		int sum = 0;
		for (int i=0; i<t.length; i++) {
			sum += (t[i] - matrix.get(0, i)) * ( t[i] - matrix.get(0, i));
		}
		return sum;
	}

	private static int[]  test(Matrix w, String file) throws IOException {
		BufferedImage image;
		StringBuffer sb = new StringBuffer();

			image = ImageIO.read(new File(file));
			 int[] p = image.getRGB(0,0,image.getWidth(),image.getHeight(),new int[image.getWidth()*image.getHeight()],0,image.getWidth());
		     for(int i=0;i<image.getHeight();i++) {
			   	for(int j=0;j<image.getWidth();j++) {
			   		System.out.print(p[i*image.getWidth()+j]==-1?" ":"*");
			   		sb.append(p[i*image.getWidth()+j]==-1?"0":"1");
			   	}
			   	System.out.println();
			 }

		
		int[] t = new int[16*16];
		
		for (int i=0; i<sb.toString().length(); i++) {
			char c = sb.charAt(i);
			if (c == '0') {
				t[i] = -1;
			} else {
				t[i] = 1;
			}
		}
		
		System.out.println("Input: " + Arrays.toString(t));
		
		int row = 0;
		int c = 0;
		int same = 0;
		String old = null;
		while (true) {
			int x = 0;
			for (int i=0; i<256; i++) {
				x += w.get(row, i) * t[i];
			}
			x = sgn(x);
			t[row] = x;
			row++;
			row = row % 256;
			c++;
			String r = Arrays.toString(t);
			if (old != null && old.equals(r)) {
				same ++; 
				if (same > 256) {
					break;
				}
			} else {
				same = 0;
			}
			old = r;
			// System.out.println(c + " = " + r);
		}
		
		System.out.println("Result = " + Arrays.toString(t));
		return t;
	}

	private static int sgn(int x) {
		if (x == 0) {
			return 0;
		}
		if (x > 0) {
			return 1;
		}
		return -1;
	}
	
}
